package gofarmlib

import (
	"encoding/json"
	"errors"
	"net"
	"time"
)

// 客户端配置选项
type Options struct {
	GatewayAddr string       // 网关地址
	UserName    string       // 用户名
	Password    string       // 密码
	Event       EventHandler // 事件处理函数
}

// 客户端
type FarmClient struct {
	Opt           Options      // 网关配置
	conn          net.Conn     // 连接实例
	connectStatus bool         // 连接状态
	CanWrite      bool         // 可写状态
	Event         EventHandler // 事件处理接口
}

// 客户端对象
var client *FarmClient

// 获取客户端实例
func Client() *FarmClient {
	return client
}

/*
打开并登录到网关
  - opt: 网关配置
*/
func Open(opt Options) (err error) {
	if client != nil && client.connectStatus {
		return
	}
	// 连接网关
	conn, err := net.Dial("tcp", opt.GatewayAddr)
	if err != nil {
		client = &FarmClient{
			Opt:           opt,
			connectStatus: false,
			Event:         opt.Event,
		}
		if client.Event != nil {
			client.Event.OnClose()
		}
		return
	} else {
		client = &FarmClient{
			Opt:           opt,
			conn:          conn,
			connectStatus: true,
			Event:         opt.Event,
		}
		if client.Event != nil {
			client.Event.OnOpen()
		}
	}
	// 登录到网关
	client.sendObjWithoutCanWrite(&GatewayData{
		ClientType: ClientType,
		MsgType:    Login,
		Body: loginRequest{
			UserName: opt.UserName,
			Password: opt.Password,
		},
	})
	// 启动一个goroutine来处理服务器发送的数据
	go handleServer(conn)
	return
}

// 网关链路检测
func StartConnectCheck() {
	go func() {
		for {
			// 每隔3秒检查一次连接状态
			time.Sleep(3 * time.Second)
			if client != nil && !client.connectStatus {
				Open(client.Opt)
			}
		}
	}()
}

// 发送数据
func (c *FarmClient) sendObjWithoutCanWrite(obj interface{}) (err error) {
	data, _ := json.Marshal(obj)
	data = append(GFrameHeaderBytes, data...)
	data = append(data, GFrameEndBytes...)
	if c.connectStatus && c.conn != nil {
		_, err = c.conn.Write(data)
		if err != nil {
			c.connectStatus = false
		}
	}
	return
}

func (c *FarmClient) sendObj(obj interface{}) (err error) {
	data, _ := json.Marshal(obj)
	data = append(GFrameHeaderBytes, data...)
	data = append(data, GFrameEndBytes...)
	if c.connectStatus && c.CanWrite && c.conn != nil {
		_, err = c.conn.Write(data)
		if err != nil {
			c.connectStatus = false
		}
	} else {
		err = errors.New("client not connect or can't write")
	}
	return
}

/*
通讯测试
  - tId: 终端ID
*/
func (c *FarmClient) Testing(tId string) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x0100,
		},
	}
	err = c.sendObj(data)
	return
}

/*
远程锁机
  - tId: 终端ID
*/
func (c *FarmClient) RemoteLocking(tId string) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x0400,
		},
	}
	err = c.sendObj(data)
	return
}

/*
远程开机
  - tId: 终端ID
*/
func (c *FarmClient) RemotePowerOn(tId string) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x0500,
		},
	}
	err = c.sendObj(data)
	return
}

/*
上传作业数据指令(追踪)
  - tId: 终端ID
*/
func (c *FarmClient) UploadJobData(tId string) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x0600,
		},
	}
	err = c.sendObj(data)
	return
}

/*
上传位置信息指令(即时定位)
  - tId: 终端ID
*/
func (c *FarmClient) UploadLocation(tId string) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x0700,
		},
	}
	err = c.sendObj(data)
	return
}

/*
恢复上一个版本
  - tId: 终端ID
*/
func (c *FarmClient) RestorePreviousVersion(tId string) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x02100,
		},
	}
	err = c.sendObj(data)
	return
}

/*
恢复出厂设置
  - tId: 终端ID
*/
func (c *FarmClient) RestoreFactorySettings(tId string) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x2200,
		},
	}
	err = c.sendObj(data)
	return
}

/*
最新固件信息
  - tId: 终端ID
  - link: 固件升级信息链接
*/
func (c *FarmClient) LatestFirmwareInfo(tId string, link string) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x2300,
		},
		Body: link,
	}
	err = c.sendObj(data)
	return
}

/*
查询指定终端参数
  - tId: 终端ID
  - idList: 参数ID列表
*/
func (c *FarmClient) QueryTerminalParamsByIds(tId string, idList []uint32) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x3000,
		},
		Body: idList,
	}
	err = c.sendObj(data)
	return
}

/*
设置终端参数
  - tId: 终端ID
  - params: 终端参数字典
*/
func (c *FarmClient) SetTerminalParams(tId string, params map[uint32]interface{}) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x3100,
		},
		Body: params,
	}
	err = c.sendObj(data)
	return
}

/*
校时
  - tId: 终端ID
*/
func (c *FarmClient) Timing(tId string) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x3200,
		},
	}
	err = c.sendObj(data)
	return
}

/*
传感器使能控制（追踪）
  - tId: 终端ID
  - ctl: 控制字节
*/
func (c *FarmClient) SensorControlData(tId string, ctl byte) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x0800,
		},
		Body: ctl,
	}
	err = c.sendObj(data)
	return
}

/*
工作状态使能控制
  - tId: 终端ID
  - ctl: 控制字节
*/
func (c *FarmClient) WorkingFuncControlData(tId string, ctl byte) (err error) {
	data := &GatewayData{
		ClientType: ClientType,
		MsgType:    Command,
		Header: MsgHeader{
			ID:    tId,
			MsgId: 0x0900,
		},
		Body: ctl,
	}
	err = c.sendObj(data)
	return
}
